package server.net.io;

import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import server.net.Client;
import server.net.handler.ServerPacketHandler;
import shared.net.protocol.ServerHeader;
import shared.net.protocol.ServerHeader.Receive;

/**
 * This class represents a work unit to give to the server's worker thread pool/
 *
 * @author Vincent Tsuei
 * @version 2012-11-16
 */
public class WorkUnit implements Runnable {

    private final ServerIOHandler serverHandler;
    private final Client client;
    private final ByteBuffer packet;

    /**
     * To properly handle a packet, the worker thread needs to know about the
     * corresponding client, the handler, and the actual packet.
     */
    public WorkUnit(ServerIOHandler serverHandler, Client client, ByteBuffer packet) {
        if (client == null) {
            throw new NullPointerException("Client is null in work unit");
        }
        if (packet == null) {
            throw new NullPointerException("Packet buffer is null in work unit");
        }

        this.serverHandler = serverHandler;
        this.client = client;
        this.packet = packet;
    }

    /**
     * Called by the worker thread pool to process this packet.
     */
    @Override
    public void run() {
        try {
            byte header = packet.get();
            Receive recvType = ServerHeader.Receive.getHeaderFromByte(header);
            if (recvType == null) {
                Logger.getLogger(WorkUnit.class.getName()).log(Level.SEVERE, "Unrecognized header received from {0} - {1}",
                        new Object[]{client.getConnection().getAddressAndPortString(), header});
                return;
            }
            ServerPacketHandler handler = serverHandler.getHandler(recvType);
            if (handler == null) {
                Logger.getLogger(WorkUnit.class.getName()).log(Level.SEVERE, "Unhandled header type - {0}",
                        new Object[]{recvType.name()});
                return;
            }

            //System.out.println(recvType + " Processing");
            int result = handler.processPacket(client, packet);
            //System.out.println(recvType + "\t" + result);
            //We may use the result in the future.
        } catch (Exception e) {
            //CATCH ALL ERRORS.
            Logger.getLogger(WorkUnit.class.getName()).log(Level.SEVERE, "EXCEPTION", e);
        }
    }
}
